<?php

namespace controller\admin;

defined('IA_ROOT') || exit();

use facade\Model;
use facade\View;
use facade\Util;

// 文章管理
class Article extends Base
{
    // 列表
    public function index()
    {
        if (Util::isAjax()) {
            $param = Util::param();
            $start = ($param['page'] - 1) * $param['limit'];
            $limit = $param['limit'];
            // $where = "`id` <= (SELECT `id` FROM `article` WHERE `status` IN (0, 1) ORDER BY `id` DESC LIMIT $start, 1)";
            $where = "1 = 1";

            // 搜索
            if (!empty($param['search'])) {
                foreach ((array)$param['search'] as $k => $v) {
                    if (strlen($v)) {
                        if (in_array($k, ['category_id', 'status'])) {
                            $where .= " AND `$k` = '$v'";
                        } else if (in_array($k, ['start', 'end'])) {
                            $timestamp = strtotime($v);
                            if ($k == 'start')
                                $where .= " AND `create_at` >= '$timestamp'";
                            else
                                $where .= " AND `create_at` <= '$timestamp'";
                        } else {
                            $where .= " AND `$k` like '%{$v}%'";
                        }
                    }
                }
            }

            // 数据库查询
            $count = Model::fetchColumn("SELECT COUNT(*) FROM `article` WHERE $where AND `lang`='{$this->lang}' AND `status` IN (0, 1) ORDER BY `id` DESC");
            $data = Model::fetchAll("SELECT * FROM `article` WHERE $where AND `lang`='{$this->lang}' AND `status` IN (0, 1) ORDER BY `id` DESC LIMIT $start, $limit");

            // 获取分类
            $category_ids = array_map(function ($item) {
                return $item['category_id'];
            }, $data);
            $idStr = $category_ids ? implode(',', $category_ids) : 0;
            $category = Model::fetchAll("SELECT * FROM `category` WHERE `id` IN ($idStr)");
            $category = Util::formatKey($category);

            // 获取标签
            $tags = array_map(function ($item) {
                return $item['tag_ids'] ? json_decode($item['tag_ids'], true) : [];
            }, $data);
            $tag_ids = [];
            foreach ($tags as $tag) {
                $tag_ids = array_merge($tag_ids, $tag);
            }
            $tag_ids = array_unique($tag_ids);
            $idStr = $tag_ids ? implode(',', $tag_ids) : 0;
            $tag = Model::fetchAll("SELECT * FROM `tag` WHERE `id` IN ($idStr)");
            $tag = Util::formatKey($tag);

            // 分页输出
            if ($count) {
                $res['code'] = 0;
            } else {
                $res['code'] = 1;
                $res['msg'] = Util::tran('暂无记录');
            }
            $res['count'] = $count;

            $res['data'] = array_map(function ($item) use ($category, $tag) {
                // 获取分类
                $item['category'] = isset($category[$item['category_id']]) ? $category[$item['category_id']]['name'] : '';
                // 获取标签
                $item['tags'] = '';
                if ($item['tag_ids']) {
                    $tag_ids = json_decode($item['tag_ids'], true);
                    $tags = [];
                    foreach ($tag_ids as $tag_id) {
                        if (isset($tag[$tag_id]))
                            $tags[] = $tag[$tag_id]['name'];
                    }
                    $item['tags'] = implode(', ', $tags);
                }
                if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $item['cover'], $match)) {
                    $item['cover'] = $this->site_url . $match[1];
                }
                if (!$item['cover'] && preg_match_all('#<img[^>]*src=(["\'])(.*?)(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $item['content'], $matches, PREG_SET_ORDER)) {
                    $item['cover'] = $this->site_url . $matches[0][3];
                }
                $item['create_at'] = date('Y-m-d H:i', $item['create_at']);
                $item['update_at'] = date('Y-m-d H:i', $item['update_at']);
                return $item;
            }, $data);
            exit(json_encode($res));
        }
        // select分类无限下拉树
        $rows = Model::fetchAll("SELECT * FROM `category` WHERE `lang`='{$this->lang}' ORDER BY `sort` DESC, `id` ASC");
        View::assign('category_tree', $this->format_tree($rows));
        View::assign('tran', [
            'title' => Util::tran('标题'),
            'input' => Util::tran('请输入'),
            'choose' => Util::tran('请选择'),
            'slug' => Util::tran('别名'),
            'description' => Util::tran('描述'),
            'cover' => Util::tran('封面'),
            'category' => Util::tran('分类'),
            'status' => Util::tran('状态'),
            'normal' => Util::tran('正常'),
            'disable' => Util::tran('禁用'),
            'author' => Util::tran('作者'),
            'date' => Util::tran('日期'),
            'delall' => Util::tran('批量删除'),
            'add' => Util::tran('添加'),
            'refresh' => Util::tran('刷新'),
            'article_list' => Util::tran('文章列表'),
            'tag' => Util::tran('标签'),
            'view' => Util::tran('浏览'),
            'likes' => Util::tran('点赞'),
            'comment' => Util::tran('评论'),
            'create_at' => Util::tran('发布时间'),
            'update_at' => Util::tran('修改时间'),
            'option' => Util::tran('操作'),
            'read' => Util::tran('阅读'),
            'edit' => Util::tran('编辑'),
            'delete' => Util::tran('删除'),
        ]);
        View::display('admin/article/index.html');
    }

    // 创建
    public function create()
    {
        $rows = Model::fetchAll("SELECT * FROM `category` WHERE `lang`='{$this->lang}' ORDER BY `sort` DESC, `id` ASC");
        $trees = $this->format_tree($rows);
        $trees = array_map(function ($item) use ($rows) {
            $item['has_children'] = array_filter($rows, function ($row) use ($item) {
                return $row['pid'] == $item['id'];
            });
            return $item;
        }, $trees);
        $tags = Model::fetchAll("SELECT * FROM `tag` WHERE `lang`='{$this->lang}' ORDER BY `id` DESC");
        View::assign(['category_tree' => $trees, 'tags' => $tags]);
        View::assign('tran', [
            'title' => Util::tran('标题'),
            'artile_title' => Util::tran('文章标题'),
            'choose' => Util::tran('请选择'),
            'input_title' => Util::tran('请输入标题'),
            'slug' => Util::tran('别名'),
            'translate' => Util::tran('翻译'),
            'content' => Util::tran('内容'),
            'input_content' => Util::tran('请输入内容'),
            'description' => Util::tran('描述'),
            'cover' => Util::tran('封面'),
            'category' => Util::tran('分类'),
            'tag' => Util::tran('标签'),
            'multi_tag' => Util::tran('多标签半角'),
            'split' => Util::tran('分割'),
            'suggest' => Util::tran('建议'),
            'keywords_suggest' => Util::tran('关键词建议'),
            'views' => Util::tran('浏览量'),
            'input_views' => Util::tran('请输入浏览量'),
            'likes' => Util::tran('点赞'),
            'input_likes' => Util::tran('请输入点赞数'),
            'author' => Util::tran('作者'),
            'input_author' => Util::tran('请输入作者'),
            'status' => Util::tran('状态'),
            'comment' => Util::tran('评论'),
            'save' => Util::tran('保存'),
            'reset' => Util::tran('重置')
        ]);
        View::display('admin/article/create.html');
    }

    // 保存
    public function save()
    {
        $param = Util::param(['title', 'slug', 'content', 'description', 'cover', 'category_id', 'tag_ids', 'tags', 'seo_title', 'seo_description', 'views', 'likes', 'author', 'status', 'can_comment']);
        (empty($param['title']) || empty($param['content'])) && Util::errMsg(Util::tran('标题或内容为空'));

        // 重复验证
        $check = Model::fetchColumn("SELECT `title` FROM `article` WHERE `title`=:title AND `lang`='{$this->lang}' ORDER BY `id`", [':title' => $param['title']]);
        $check && Util::errMsg(Util::tran('标题重名'));
        if (!empty($param['slug'])) {
            $param['slug'] = preg_replace('/[\W]/', ' ', $param['slug']);
            $param['slug'] = preg_replace('/\s+/', ' ', $param['slug']);
            $param['slug'] = strtolower($param['slug']);
            $param['slug'] = str_replace(' ', '-', $param['slug']);
            !preg_match('#^[a-z0-9_-]{2,200}$#i', $param['slug']) && Util::errMsg(Util::tran('别名只能英文字母数字下划线中划线，位数') . ' 2~200');
            $check = Model::fetchColumn("SELECT `slug` FROM `article` WHERE `slug`=:slug AND `lang`='{$this->lang}' ORDER BY `id`", [':slug' => $param['slug']]);
            $check && Util::errMsg(Util::tran('别名重复'));
        }

        if (!empty($param['cover'])) {
            !preg_match('/\.(gif|jpe?g|png|bmp|webp|psd|svg|tiff)$/i', $param['cover']) && Util::errMsg(Util::tran('图片格式错误'));
            if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $param['cover'], $match)) {
                $param['cover'] = $match[1];
            }
        }

        // 检查子分类
        $check = Model::fetch("SELECT * FROM `category` WHERE `pid`=:pid AND `lang`='{$this->lang}'", [':pid' => $param['category_id']]);
        $check && Util::errMsg(Util::tran('请选择子分类'));
        if (empty($param['author']))
            $param['author'] = 'admin';
        $check = Model::fetch("SELECT `id`, `status` FROM `user` WHERE `username` = :author", [':author' => $param['author']]);
        (!$check || $check['status']) && Util::errMsg(Util::tran('作者名未注册或被禁用'));

        // 数据处理
        !in_array($this->lang, $this->user['langs']) && Util::errMsg(Util::tran('没有语言权限，请联系管理员'));
        $tag_ids = isset($param['tag_ids']) ? $param['tag_ids'] : [];
        if ($param['tags']) {
            $tags = explode(',', $param['tags']);
            $tags = array_map('trim', $tags);
            $tags = array_filter($tags);
            $tagStr = $tags ? implode("','", $tags) : '0';
            $tag = Model::fetchAll("SELECT `id`, `name` FROM `tag` WHERE `name` IN ('$tagStr') AND `lang`='{$this->lang}' ORDER BY `id` DESC");
            if ($tag) {
                $ids = array_map(function ($item) {
                    return $item['id'];
                }, $tag);
                $tag_ids = array_merge($ids, $tag_ids);
                $tag_ids = array_unique($tag_ids);
                // 过滤已存在的标签
                $tags = array_filter($tags, function ($item) use ($tag) {
                    return !in_array($item, array_map(function ($elem) {
                        return $elem['name'];
                    }, $tag));
                });
            }
            // 添加未存在的标签
            foreach ($tags as $_tag) {
                $lastInsertId = Model::insert('tag', ['name' => $_tag, 'time' => time(), 'lang' => $this->lang]);
                if ($lastInsertId) {
                    array_push($tag_ids, $lastInsertId);
                    $this->log(Util::tran('创建文章时标签'), Util::tran('添加文章时创建标签') . " {$_tag} " . Util::tran('成功'), 0);
                } else {
                    $this->log(Util::tran('创建文章时标签'), Util::tran('添加文章时创建标签') . " {$_tag} " . Util::tran('失败'), 1);
                }
            }
        }
        unset($param['tags']);
        if ($tag_ids) {
            $tag_ids = array_values($tag_ids);
            $tag_ids = array_map('strval', $tag_ids);
            $param['tag_ids'] = json_encode($tag_ids);
        } else
            $param['tag_ids'] = '';

        // 写入数据库记录日志
        $param['create_at'] = time();
        $param['update_at'] = time();
        $param['lang'] = $this->lang;
        if (preg_match_all('#<[^>]*=(["\'])(.*?)(/static/(res|upload)/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $param['content'], $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                $param['content'] = str_replace($match[2] . $match[3], $match[3], $param['content']);
            }
        }
        $lastInsertId = Model::insert('article', $param);
        if ($lastInsertId) {
            // 修改媒体状态
            $paths = [0 => [], 2 => []];
            if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $param['cover'], $match)) {
                if (is_file(IA_ROOT . $match[1]))
                    $paths[0][] = $match[1];
                else
                    $paths[2][] = $match[1];
            }
            if (preg_match_all('#<[^>]*=(["\'])(.*?)(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $param['content'], $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (is_file(IA_ROOT . $match[3]))
                        $paths[0][] = $match[3];
                    else
                        $paths[2][] = $match[3];
                }
            }
            $paths[0] && Model::update('media', ['status' => 0], ['path' => $paths[0]]);
            $paths[2] && Model::update('media', ['status' => 2], ['path' => $paths[2]]);
            // 更新文章数量
            $param['category_id'] && Model::update('category', 'num = num + 1', ['id' => $param['category_id']]);
            $tag_ids && Model::update('tag', 'num = num + 1', ['id' => $tag_ids]);
            if ($param['status'] == '1') {
                $param['category_id'] && Model::update('category', 'num = num - 1', ['id' => $param['category_id']]);
                $tag_ids && Model::update('tag', 'num = num - 1', ['id' => $tag_ids]);
            }
            // 清除缓存
            $this->clearCache($lastInsertId);
            $this->log(Util::tran('创建文章'), Util::tran('创建文章') . " {$param['title']} " . Util::tran('成功'), 0);
            Util::errMsg(['code' => 0, 'msg' => Util::tran('创建文章成功'), 'url' => Util::url("/{$this->lang}/admin/article/index.html")]);
        } else {
            $this->log(Util::tran('创建文章'), Util::tran('创建文章') . " {$param['title']} " . Util::tran('失败'), 1);
            Util::errMsg(['code' => 1, 'msg' => Util::tran('创建文章失败')]);
        }
    }

    // 编辑
    public function edit($id = 0)
    {
        $row = Model::fetch("SELECT * FROM `article` WHERE `id`=:id", [':id' => $id]);
        !$row && Util::errMsg('ID ' . Util::tran('错误'));
        if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $row['cover'], $match)) {
            $row['cover'] = $this->subdir . $match[1];
        }
        if (preg_match_all('#<[^>]*=(["\'])(.*?)(/static/(res|upload)/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $row['content'], $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                $row['content'] = str_replace($match[2] . $match[3], $this->subdir . $match[3], $row['content']);
            }
        }
        $tag_ids = $row['tag_ids'] ? json_decode($row['tag_ids'], true) : [];
        $rows = Model::fetchAll("SELECT * FROM `category` WHERE `lang`='{$this->lang}' ORDER BY `sort` DESC, `id` ASC");
        $trees = $this->format_tree($rows);
        $trees = array_map(function ($item) use ($rows) {
            $item['has_children'] = array_filter($rows, function ($row) use ($item) {
                return $row['pid'] == $item['id'];
            });
            return $item;
        }, $trees);
        $tags = Model::fetchAll("SELECT * FROM `tag` WHERE `lang`='{$this->lang}' ORDER BY `id` DESC");
        View::assign(['row' => $row, 'tag_ids' => $tag_ids, 'category_tree' => $trees, 'tags' => $tags]);
        View::assign('tran', [
            'title' => Util::tran('标题'),
            'choose' => Util::tran('请选择'),
            'artile_title' => Util::tran('文章标题'),
            'input_title' => Util::tran('请输入标题'),
            'slug' => Util::tran('别名'),
            'translate' => Util::tran('翻译'),
            'content' => Util::tran('内容'),
            'input_content' => Util::tran('请输入内容'),
            'description' => Util::tran('描述'),
            'cover' => Util::tran('封面'),
            'category' => Util::tran('分类'),
            'tag' => Util::tran('标签'),
            'multi_tag' => Util::tran('多标签半角'),
            'split' => Util::tran('分割'),
            'suggest' => Util::tran('建议'),
            'keywords_suggest' => Util::tran('关键词建议'),
            'views' => Util::tran('浏览量'),
            'input_views' => Util::tran('请输入浏览量'),
            'likes' => Util::tran('点赞'),
            'input_likes' => Util::tran('请输入点赞数'),
            'author' => Util::tran('作者'),
            'input_author' => Util::tran('请输入作者'),
            'status' => Util::tran('状态'),
            'comment' => Util::tran('评论'),
            'save' => Util::tran('保存'),
            'reset' => Util::tran('重置'),
        ]);
        View::display('admin/article/edit.html');
    }

    // 更新
    public function update()
    {
        $param = Util::param(['id', 'title', 'slug', 'content', 'description', 'cover', 'category_id', 'tag_ids', 'tags', 'seo_title', 'seo_description', 'views', 'likes', 'author', 'status', 'can_comment']);
        (empty($param['title']) || empty($param['content'])) && Util::errMsg(Util::tran('标题或内容为空'));
        $row = Model::fetch("SELECT * FROM `article` WHERE `id`=:id", [':id' => $param['id']]);
        !$row && Util::errMsg('ID ' . Util::tran('错误'));

        // 重复验证
        $check = Model::fetchColumn("SELECT `title` FROM `article` WHERE `title`=:title AND `lang`='{$this->lang}' ORDER BY `id`", [':title' => $param['title']]);
        $check && $check !== $row['title'] && Util::errMsg(Util::tran('标题重名'));
        if (!empty($param['slug'])) {
            $param['slug'] = preg_replace('/[\W]/', ' ', $param['slug']);
            $param['slug'] = preg_replace('/\s+/', ' ', $param['slug']);
            $param['slug'] = strtolower($param['slug']);
            $param['slug'] = str_replace(' ', '-', $param['slug']);
            !preg_match('#^[a-z0-9_-]{2,200}$#i', $param['slug']) && Util::errMsg(Util::tran('别名只能英文字母数字下划线中划线，位数') . ' 2~200');
            $check = Model::fetchColumn("SELECT `slug` FROM `article` WHERE `slug`=:slug AND `lang`='{$this->lang}' ORDER BY `id`", [':slug' => $param['slug']]);
            $check && $check !== $row['slug'] && Util::errMsg(Util::tran('别名重复'));
        }

        if (!empty($param['cover'])) {
            !preg_match('/\.(gif|jpe?g|png|bmp|webp|psd|svg|tiff)$/i', $param['cover']) && Util::errMsg(Util::tran('图片格式错误'));
            if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $param['cover'], $match)) {
                $param['cover'] = $match[1];
            }
        }

        // 检查子分类
        $check = Model::fetch("SELECT * FROM `category` WHERE `pid`=:pid AND `lang`='{$this->lang}'", [':pid' => $param['category_id']]);
        $check && Util::errMsg(Util::tran('请选择子分类'));
        if (empty($param['author']))
            $param['author'] = 'admin';
        $check = Model::fetch("SELECT `status` FROM `user` WHERE `username` = :author", [':author' => $param['author']]);
        (!$check || $check['status']) && Util::errMsg(Util::tran('作者名未注册或被禁用'));

        // 数据处理
        !in_array($this->lang, $this->user['langs']) && Util::errMsg(Util::tran('没有语言权限，请联系管理员'));
        $tag_ids = isset($param['tag_ids']) ? $param['tag_ids'] : [];
        if ($param['tags']) {
            $tags = explode(',', $param['tags']);
            $tags = array_map('trim', $tags);
            $tags = array_filter($tags);
            $tagStr = $tags ? implode("','", $tags) : '0';
            $tag = Model::fetchAll("SELECT `id`, `name` FROM `tag` WHERE `name` IN ('$tagStr') AND `lang`='{$this->lang}' ORDER BY `id` DESC");
            if ($tag) {
                $ids = array_map(function ($item) {
                    return $item['id'];
                }, $tag);
                $tag_ids = array_merge($ids, $tag_ids);
                $tag_ids = array_unique($tag_ids);
                // 过滤已存在的标签
                $tags = array_filter($tags, function ($item) use ($tag) {
                    return !in_array($item, array_map(function ($elem) {
                        return $elem['name'];
                    }, $tag));
                });
            }
            // 添加未存在的标签
            foreach ($tags as $_tag) {
                $lastInsertId = Model::insert('tag', ['name' => $_tag, 'time' => time(), 'lang' => $this->lang]);
                if ($lastInsertId) {
                    array_push($tag_ids, $lastInsertId);
                    $this->log(Util::tran('编辑文章时标签'), Util::tran('编辑文章时标签') . " {$_tag} " . Util::tran('成功'), 0);
                } else {
                    $this->log(Util::tran('编辑文章时标签'), Util::tran('编辑文章时标签') . " {$_tag} " . Util::tran('失败'), 1);
                }
            }
        }
        unset($param['tags']);
        if ($tag_ids) {
            $tag_ids = array_values($tag_ids);
            $tag_ids = array_map('strval', $tag_ids);
            $param['tag_ids'] = json_encode($tag_ids);
        } else
            $param['tag_ids'] = '';

        // 更新数据库记录日志
        // $param['update_at'] = time();
        if (preg_match_all('#<[^>]*=(["\'])(.*?)(/static/(res|upload)/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $param['content'], $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                $param['content'] = str_replace($match[2] . $match[3], $match[3], $param['content']);
            }
        }
        $rowCount = Model::update('article', $param, ['id' => $param['id']]);

        // 修改媒体状态
        $paths = [0 => [], 1 => [], 2 => []];
        if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $row['cover'], $match)) {
            if (is_file(IA_ROOT . $match[1]))
                $paths[1][] = $match[1];
            else
                $paths[2][] = $match[1];
        }
        if (preg_match_all('#<[^>]*=(["\'])(.*?)(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $row['content'], $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                if (is_file(IA_ROOT . $match[3]))
                    $paths[1][] = $match[3];
                else
                    $paths[2][] = $match[3];
            }
        }
        if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $param['cover'], $match)) {
            if (is_file(IA_ROOT . $match[1]))
                $paths[0][] = $match[1];
            else
                $paths[2][] = $match[1];
        }
        if (preg_match_all('#<[^>]*=(["\'])(.*?)(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $param['content'], $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                if (is_file(IA_ROOT . $match[3]))
                    $paths[0][] = $match[3];
                else
                    $paths[2][] = $match[3];
            }
        }
        $paths[1] = array_filter($paths[1], function ($item) use ($paths) {
            return !in_array($item, $paths[0]);
        });
        $paths[1] && Model::update('media', ['status' => 1], ['path' => array_unique($paths[1])]);
        $paths[0] && Model::update('media', ['status' => 0], ['path' => array_unique($paths[0])]);
        $paths[2] && Model::update('media', ['status' => 2], ['path' => array_unique($paths[2])]);
        if ($rowCount) {
            // 更新文章数量
            if ($row['category_id'] !== $param['category_id']) {
                Model::update('category', 'num = num - 1', ['id' => $row['category_id']]);
                Model::update('category', 'num = num + 1', ['id' => $param['category_id']]);
            }
            if ($row['status'] !== $param['status']) {
                if ($param['status'] == '1') {
                    Model::update('category', 'num = num - 1', ['id' => $param['category_id']]);
                } else if ($param['status'] == '0') {
                    Model::update('category', 'num = num + 1', ['id' => $param['category_id']]);
                }
            }
            $prev_ids = [];
            $next_ids = [];
            if ($row['tag_ids'] !== $param['tag_ids']) {
                $ids = [];
                if ($row['tag_ids']) {
                    $ids = json_decode($row['tag_ids'], true);
                }
                foreach ($ids as $id) {
                    if (!in_array($id, $tag_ids))
                        $prev_ids[] = $id;
                }
                foreach ($tag_ids as $id) {
                    if (!in_array($id, $ids))
                        $next_ids[] = $id;
                }
                $prev_ids && Model::update('tag', 'num = num - 1', ['id' => $prev_ids]);
                $next_ids && Model::update('tag', 'num = num + 1', ['id' => $next_ids]);
            }
            if ($row['status'] !== $param['status']) {
                if ($param['status'] == '1') {
                    $next_ids && Model::update('tag', 'num = num - 1', ['id' => $next_ids]);
                } else if ($param['status'] == '0') {
                    $next_ids && Model::update('tag', 'num = num + 1', ['id' => $next_ids]);
                }
            }
            Model::update('article', ['update_at' => time()], ['id' => $param['id']]);
            // 清除缓存
            $this->clearCache($param['id']);
            $this->log(Util::tran('编辑文章'), Util::tran('编辑文章') . " {$row['title']} -> {$param['title']} " . Util::tran('成功'), 0);
            Util::errMsg(['code' => 0, 'msg' => Util::tran('编辑文章成功'), 'url' => Util::url("/{$this->lang}/admin/article/index.html")]);
        } else {
            $this->log(Util::tran('编辑文章'), Util::tran('没有改变') . " {$row['title']} " . Util::tran('信息'), 0);
            Util::errMsg(['code' => 1, 'msg' => Util::tran('没有改变信息')]);
        }
    }

    // 修改属性
    public function modify()
    {
        $param = Util::param(['id', 'field', 'value']);
        empty($param['id']) && Util::errMsg('ID ' . Util::tran('错误'));
        $row = Model::fetch("SELECT * FROM `article` WHERE `id`=:id", [':id' => $param['id']]);
        !$row && Util::errMsg('ID ' . Util::tran('非法'));
        (empty($param['field']) || !in_array($param['field'], ['title', 'slug', 'description', 'views', 'likes', 'author', 'status', 'can_comment'])) && Util::errMsg(Util::tran('非法字段'));

        // 验证字段
        if ($param['field'] == 'title') {
            empty($param['value']) && Util::errMsg(Util::tran('标题不能为空'));
            $check = Model::fetchColumn("SELECT `title` FROM `article` WHERE `title`=:title AND `lang`='{$this->lang}' ORDER BY `id`", [':title' => $param['value']]);
            $check && $check !== $row['title'] && Util::errMsg(Util::tran('标题重名'));
        }
        if ($param['field'] == 'slug') {
            $param['value'] = preg_replace('/[\W]/', ' ', $param['value']);
            $param['value'] = preg_replace('/\s+/', ' ', $param['value']);
            $param['value'] = strtolower($param['value']);
            $param['value'] = str_replace(' ', '-', $param['value']);
            !preg_match('#^[a-z0-9_-]{2,200}$#i', $param['value']) && Util::errMsg(Util::tran('别名只能英文字母数字下划线中划线，位数') . ' 2~200');
            $check = Model::fetchColumn("SELECT `slug` FROM `article` WHERE `slug`=:slug AND `lang`='{$this->lang}' ORDER BY `id`", [':slug' => $param['value']]);
            $check && $check !== $row['slug'] && Util::errMsg(Util::tran('别名重复'));
        }
        if (in_array($param['field'], ['views', 'likes'])) {
            !is_numeric($param['value']) && Util::errMsg(Util::tran('填写整数'));
        }
        if ($param['field'] == 'author') {
            $check = Model::fetch("SELECT `status` FROM `user` WHERE `username` = :author", [':author' => $param['value']]);
            (!$check || $check['status']) && Util::errMsg(Util::tran('作者名未注册或被禁用'));
        }

        !in_array($this->lang, $this->user['langs']) && Util::errMsg(Util::tran('没有语言权限，请联系管理员'));
        if ($param['field'] == 'status') {
            if ($row['status'] != $param['value']) {
                $category_ids = $row['category_id'];
                $tag_ids = $row['tag_ids'] ? json_decode($row['tag_ids'], true) : [];
                if ($param['value'] == '1') {
                    $category_ids && Model::update('category', 'num = num - 1', ['id' => $category_ids]);
                    $tag_ids && Model::update('tag', 'num = num - 1', ['id' => $tag_ids]);
                } else if ($param['value'] == '0') {
                    $category_ids && Model::update('category', 'num = num + 1', ['id' => $category_ids]);
                    $tag_ids && Model::update('tag', 'num = num + 1', ['id' => $tag_ids]);
                }
            }
        }

        // 更新数据库记录日志
        $rowCount = Model::update('article', [$param['field'] => $param['value'], 'update_at' => time()], ['id' => $param['id']]);
        if ($rowCount) {
            // 清除文章缓存
            $this->clearCache($param['id']);
            $this->log(Util::tran('修改属性'), Util::tran('修改属性') . " {$param['field']}: {$row[$param['field']]} -> {$param['value']} " . Util::tran('成功'), 0);
            Util::errMsg(['code' => 0, 'msg' => Util::tran('修改成功')]);
        } else {
            $this->log(Util::tran('修改属性'), Util::tran('修改属性') . " {$param['field']}: {$row[$param['field']]} -> {$param['value']} " . Util::tran('失败'), 1);
            Util::errMsg(['code' => 1, 'msg' => Util::tran('修改失败')]);
        }
    }

    // 软删除
    public function delete()
    {
        $param = Util::param(['id']);
        (empty($param) || !isset($param['id'])) && Util::errMsg(Util::tran('请选择数据'));
        $idStr = $param['id'] ? implode(',', (array)$param['id']) : 0;
        $rows = Model::fetchAll("SELECT `title`, `category_id`, `tag_ids` FROM `article` WHERE `id` IN ($idStr) AND `status` IN (0, 1)  AND `lang`='{$this->lang}'");
        $names = [];
        $category_ids = [];
        $tag_ids = [];
        foreach ($rows as $row) {
            $names[] = $row['title'];
            $category_ids[] = $row['category_id'];
            if ($row['tag_ids'])
                $tag_ids = array_merge($tag_ids, json_decode($row['tag_ids'], true));
        }
        $category_ids = array_unique($category_ids);
        $tag_ids = array_unique($tag_ids);

        // 软删除数据记录日志
        !in_array($this->lang, $this->user['langs']) && Util::errMsg(Util::tran('没有语言权限，请联系管理员'));
        $rowCount = Model::update('article', ['status' => 2], ['id' => $param['id']]);
        if ($rowCount) {
            // 更新文章数量
            $category_ids && Model::update('category', 'num = num - 1', ['id' => $category_ids]);
            $tag_ids && Model::update('tag', 'num = num - 1', ['id' => $tag_ids]);
            // 清除文章缓存
            $this->clearCache($param['id']);
            $this->log(Util::tran('软删除文章'), Util::tran('软删除文章') . " " . implode(' ', $names) . " " . Util::tran('成功'), 0);
            Util::errMsg(['code' => 0, 'msg' => Util::tran('软删除成功')]);
        } else {
            $this->log(Util::tran('软删除文章'), Util::tran('软删除文章') . " " . implode(' ', $names) . " " . Util::tran('失败'), 1);
            Util::errMsg(['code' => 1, 'msg' => Util::tran('软删除失败')]);
        }
    }

    // 回收站
    public function recycle()
    {
        if (Util::isAjax()) {
            $param = Util::param();
            $start = ($param['page'] - 1) * $param['limit'];
            $limit = $param['limit'];
            // $where = "`id` <= (SELECT `id` FROM `article` WHERE `status` = 2 ORDER BY `id` DESC LIMIT $start, 1)";
            $where = "1 = 1";

            // 搜索
            if (!empty($param['search'])) {
                foreach ((array)$param['search'] as $k => $v) {
                    if (strlen($v)) {
                        if (in_array($k, ['category_id', 'status'])) {
                            $where .= " AND `$k` = '$v'";
                        } else if (in_array($k, ['start', 'end'])) {
                            $timestamp = strtotime($v);
                            if ($k == 'start')
                                $where .= " AND `create_at` >= '$timestamp'";
                            else
                                $where .= " AND `create_at` <= '$timestamp'";
                        } else {
                            $where .= " AND `$k` like '%{$v}%'";
                        }
                    }
                }
            }

            // 数据库查询
            $count = Model::fetchColumn("SELECT COUNT(*) FROM `article` WHERE $where AND `lang`='{$this->lang}' AND `status` = 2 ORDER BY `id` DESC");
            $data = Model::fetchAll("SELECT * FROM `article` WHERE $where AND `lang`='{$this->lang}' AND `status` = 2 ORDER BY `id` DESC LIMIT $start, $limit");

            // 获取分类
            $category_ids = array_map(function ($item) {
                return $item['category_id'];
            }, $data);
            $idStr = $category_ids ? implode(',', $category_ids) : 0;
            $category = Model::fetchAll("SELECT * FROM `category` WHERE `id` IN ($idStr) AND `lang`='{$this->lang}'");
            $category = Util::formatKey($category);

            // 获取标签
            $tags = array_map(function ($item) {
                return $item['tag_ids'] ? json_decode($item['tag_ids'], true) : [];
            }, $data);
            $tag_ids = [];
            foreach ($tags as $tag) {
                $tag_ids = array_merge($tag_ids, $tag);
            }
            $tag_ids = array_unique($tag_ids);
            $idStr = $tag_ids ? implode(',', $tag_ids) : 0;
            $tag = Model::fetchAll("SELECT * FROM `tag` WHERE `id` IN ($idStr) AND `lang`='{$this->lang}'");
            $tag = Util::formatKey($tag);

            // 分页输出
            if ($count) {
                $res['code'] = 0;
            } else {
                $res['code'] = 1;
                $res['msg'] = Util::tran('暂无记录');
            }
            $res['count'] = $count;

            $res['data'] = array_map(function ($item) use ($category, $tag) {
                // 获取分类
                $item['category'] = isset($category[$item['category_id']]) ? $category[$item['category_id']]['name'] : '';
                // 获取标签
                $item['tags'] = '';
                if ($item['tag_ids']) {
                    $tag_ids = json_decode($item['tag_ids'], true);
                    $tags = [];
                    foreach ($tag_ids as $tag_id) {
                        if (isset($tag[$tag_id]))
                            $tags[] = $tag[$tag_id]['name'];
                    }
                    $item['tags'] = implode(', ', $tags);
                }
                if (!$item['cover'] && preg_match_all('#<img[^>]*src=(["\'])(.*?)(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $item['content'], $matches, PREG_SET_ORDER)) {
                    $item['cover'] = $this->site_url . $matches[0][3];
                }
                if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $item['cover'], $match)) {
                    $item['cover'] = $this->site_url . $match[1];
                }
                $item['create_at'] = date('Y-m-d H:i', $item['create_at']);
                $item['update_at'] = date('Y-m-d H:i', $item['update_at']);
                return $item;
            }, $data);
            exit(json_encode($res));
        }
        // select分类无限下拉树
        $rows = Model::fetchAll("SELECT * FROM `category` WHERE `lang`='{$this->lang}' ORDER BY `sort` DESC, `id` ASC");
        View::assign('category_tree', $this->format_tree($rows));
        View::assign('tran', [
            'title' => Util::tran('标题'),
            'input' => Util::tran('请输入'),
            'choose' => Util::tran('请选择'),
            'slug' => Util::tran('别名'),
            'description' => Util::tran('描述'),
            'cover' => Util::tran('封面'),
            'category' => Util::tran('分类'),
            'author' => Util::tran('作者'),
            'date' => Util::tran('日期'),
            'delall' => Util::tran('批量删除'),
            'restore_all' => Util::tran('批量还原'),
            'refresh' => Util::tran('刷新'),
            'recycle' => Util::tran('回收站'),
            'tag' => Util::tran('标签'),
            'view' => Util::tran('浏览'),
            'likes' => Util::tran('点赞'),
            'comment' => Util::tran('评论'),
            'create_at' => Util::tran('发布时间'),
            'update_at' => Util::tran('修改时间'),
            'option' => Util::tran('操作'),
            'restore' => Util::tran('还原'),
            'delete' => Util::tran('删除'),
        ]);
        View::display('admin/article/recycle.html');
    }

    // 还原
    public function restore()
    {
        $param = Util::param(['id']);
        (empty($param) || !isset($param['id'])) && Util::errMsg(Util::tran('请选择数据'));
        $idStr = implode(',', (array)$param['id']);
        $rows = Model::fetchAll("SELECT `title`, `category_id`, `tag_ids` FROM `article` WHERE `id` IN ($idStr) AND `lang`='{$this->lang}' AND `status` = 2");
        $names = [];
        $category_ids = [];
        $tag_ids = [];
        foreach ($rows as $row) {
            $names[] = $row['title'];
            $category_ids[] = $row['category_id'];
            if ($row['tag_ids'])
                $tag_ids = array_merge($tag_ids, json_decode($row['tag_ids'], true));
        }
        $category_ids = array_unique($category_ids);
        $tag_ids = array_unique($tag_ids);

        // 软删除数据还原并记录日志
        !in_array($this->lang, $this->user['langs']) && Util::errMsg(Util::tran('没有语言权限，请联系管理员'));
        $rowCount = Model::update('article', ['status' => 0], ['id' => $param['id']]);
        if ($rowCount) {
            // 更新文章数量
            $category_ids && Model::update('category', 'num = num + 1', ['id' => $category_ids]);
            $tag_ids && Model::update('tag', 'num = num + 1', ['id' => $tag_ids]);
            // 清除文章缓存
            $this->clearCache($param['id']);
            $this->log(Util::tran('还原文章'), Util::tran('还原文章') . " " . implode(' ', $names) . " " . Util::tran('成功'), 0);
            Util::errMsg(['code' => 0, 'msg' => Util::tran('还原成功')]);
        } else {
            $this->log(Util::tran('还原文章'), Util::tran('还原文章') . " " . implode(' ', $names) . " " . Util::tran('失败'), 1);
            Util::errMsg(['code' => 1, 'msg' => Util::tran('还原失败')]);
        }
    }

    // 彻底删除
    public function destroy()
    {
        $param = Util::param(['id']);
        (empty($param) || !isset($param['id'])) && Util::errMsg(Util::tran('请选择数据'));
        $idStr = implode(',', (array)$param['id']);
        $rows = Model::fetchAll("SELECT `title`, `category_id`, `tag_ids`, `cover`, `content` FROM `article` WHERE `id` IN ($idStr) AND `lang`='{$this->lang}' AND `status` = 2");
        $names = [];
        $paths = [1 => [], 2 => []];
        foreach ($rows as $row) {
            $names[] = $row['title'];
            if (preg_match('#(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)#i', $row['cover'], $match)) {
                if (is_file(IA_ROOT . $match[1]))
                    $paths[1][] = $match[1];
                else
                    $paths[2][] = $match[1];
            }
            if (preg_match_all('#<[^>]*=(["\'])(.*?)(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#', $row['content'], $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (is_file(IA_ROOT . $match[3]))
                        $paths[1][] = $match[3];
                    else
                        $paths[2][] = $match[3];
                }
            }
        }

        // 彻底删除数据并记录日志
        !in_array($this->lang, $this->user['langs']) && Util::errMsg(Util::tran('没有语言权限，请联系管理员'));
        $rowCount = Model::delete('article', ['id' => $param['id']]);
        if ($rowCount) {
            // 清除文章缓存
            $this->clearCache($param['id']);
            $this->log(Util::tran('删除文章'), Util::tran('删除文章') . " " . implode(' ', $names) . " " . Util::tran('成功'), 0);
            // 删除文章评论
            $idStr = implode(',', (array)$param['id']);
            $comments = Model::fetchAll("SELECT * FROM `comment` WHERE `article_id` in ($idStr) ORDER BY `id` DESC");
            $comNames = [];
            foreach ($comments as $comment) {
                $comNames[] = mb_strimwidth(preg_replace('/\s+/sim', ' ', strip_tags($comment['comment'])), 0, 60, '...', 'UTF-8');
                if (preg_match_all('#<[^>]*=(["\'])(.*?)(/static/upload/[^\s"\'<>]+?\.[^\s"\'<>]+)\1#i', $comment['comment'], $matches, PREG_SET_ORDER)) {
                    foreach ($matches as $match) {
                        if (is_file(IA_ROOT . $match[3]))
                            $paths[1][] = $match[3];
                        else
                            $paths[2][] = $match[3];
                    }
                }
                Model::delete('comment', ['id' => $comment['id']]);
            }
            // 修改媒体状态
            $paths[1] && Model::update('media', ['status' => 1], ['path' => array_unique($paths[1])]);
            $paths[2] && Model::update('media', ['status' => 2], ['path' => array_unique($paths[2])]);
            $comNames && $this->log(Util::tran('删除文章时删除评论'), Util::tran('删除文章时删除评论') . " " . implode(' ', $comNames) . " " . Util::tran('成功'), 0);
            Util::errMsg(['code' => 0, 'msg' => Util::tran('删除成功')]);
        } else {
            $this->log(Util::tran('删除文章'), Util::tran('删除文章') . " " . implode(' ', $names) . " " . Util::tran('失败'), 1);
            Util::errMsg(['code' => 1, 'msg' => Util::tran('删除失败')]);
        }
    }

    // 删除缓存
    private function clearCache($ids = 0, $type = 'article')
    {
        if ($ids) {
            $ids = (array)$ids;
            $ids = array_unique($ids);
            $idStr = implode(',', $ids);
            $rows = Model::fetchAll("SELECT * FROM `$type` WHERE `id` IN ($idStr)");
            $prefix = $this->site_url . ($this->lang === 'zh-CN' ? "/" : "/{$this->lang}/");
            $cat_ids = [];
            $tag_ids = [];
            foreach ($rows as $row) {
                $count = 0;
                if ($type == 'article') {
                    // 分类
                    $cat_ids[] = $row['category_id'];
                    $cat_ids = array_unique($cat_ids);
                    // 标签
                    $tags = (array)json_decode($row['tag_ids'], true);
                    $tags = array_map('intval', $tags);
                    $tag_ids = array_merge($tag_ids, $tags);
                    $tag_ids = array_unique($tag_ids);
                    // 评论
                    $count = Model::fetchColumn("SELECT COUNT(*) FROM `comment` WHERE `pid`=0 AND `article_id`=:article_id AND `status`=0 ORDER BY `id` DESC", [':article_id' => $row['id']]);
                } else if ($type == 'category') {
                    $count = Model::fetchColumn("SELECT COUNT(*) FROM `article` WHERE `category_id`=:category_id AND `status`=0 ORDER BY `id` DESC", [':category_id' => $row['id']]);
                } else if ($type == 'tag') {
                    $count = Model::fetchColumn("SELECT COUNT(*) FROM `article` WHERE `tag_ids` like '%\"{$row['id']}\"%' AND `status`=0 ORDER BY `id` DESC");
                }
                $file_name = md5($prefix);
                $cache_file = IA_ROOT . '/mvc/tpl/' . substr($file_name, 0, 2) . '/' . $file_name . '.php';
                file_exists($cache_file) && unlink($cache_file);
                $file_name = md5($prefix . ($type === 'article' ? '' : $type . '/') . ($row['slug'] ? $row['slug'] : $row['id']) . '.html');
                $cache_file = IA_ROOT . '/mvc/tpl/' . substr($file_name, 0, 2) . '/' . $file_name . '.php';
                file_exists($cache_file) && unlink($cache_file);
                // 删除分页缓存
                for ($i = 2; $i <= ceil($count / 10); $i++) {
                    $file_name = md5($prefix . ($type === 'article' ? '' : $type . '/') . ($row['slug'] ? $row['slug'] : $row['id']) . '/page-' . $i . '.html');
                    $cache_file = IA_ROOT . '/mvc/tpl/' . substr($file_name, 0, 2) . '/' . $file_name . '.php';
                    file_exists($cache_file) && unlink($cache_file);
                }
                // 删除下载内容
                if ($type === 'article') {
                    foreach (glob(IA_ROOT . '/static/upload/articles/ID' . str_pad($row['id'], 7, '0', STR_PAD_LEFT) . '-*') as $file) {
                        unlink($file);
                    }
                }
            }
            $cat_ids && $this->clearCache($cat_ids, 'category');
            $tag_ids && $this->clearCache($tag_ids, 'tag');
        }
    }
}
